设计模式系列(开篇):啥是设计模式?
大家好,我是mbb。
前端时间,花了一段时间去整理并开发了一个用于刷面试题的小程序;整理各种资料,耗费了比较多的时间,虽然还有更多的资料需要整理,决定暂时换个方式,缓解缓解,来整理一下设计模式系列。
都说天下武功,无坚不摧,唯快不破!不仅武林中适用这个法则,编程、写代码同样也不例外;
能快速开发需求,能及时应对bug,能轻松搞定调整,你自然就能升值加薪,担任总经理,出任CEO,赢取白富美,走向人生巅峰。
那如何才能快呢?武林高手几乎个个都是内力深厚;那程序员的内力该如何修炼呢?我觉得,「设计模式」就是其中的一本盖世神功的武功秘籍;
接下来的一段时间,会围绕着设计模式展开一个系列的文章,来好好梳理一下这块儿;
整体会围绕下面这张图的各个点展开:
什么是设计模式
「设计模式」(Design Pattern)是前辈们对「代码开发经验的总结」,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性
、可维护性
、可读性
、稳健性
以及安全性
的解决方案。
通俗点说,就是前人栽树,后人乘凉!你现在遇到的坑已经早就被别人踩过并且给解决了,解决完之后,他们还将经验教训总结并分享了出来;你需要做的就是,将这些经验学会,并且运用到实际的开发中,那么你的盖世绝学就算是练成了。
❝《Design Patterns: Elements of Reusable Object-Oriented Software》(《设计模式》)),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著(Addison-Wesley,1995)。共收录了「23 种设计模式」;这几位作者常被称为"「四人组」(Gang of Four)",而这本书也就被称为"四人组(或 GoF)"书。 -----来源于【百度百科】
❞
什么样的代码才是优秀的呢?
「复用性强」
“「明天上线」”我想是开发人员经常会听到的一个“成语”;我们不能一味的怪产品经理、领导为难我们;很多时候,商场如战场,机会、商机稍纵即逝;因此就得争分夺秒的在第一时间将产品推出来;
那作为开发人员,如何去应对这种压力呢?
可以将之前已经写过的代码复用起来,减少不必要的重复工作,让我们能专心去面对业务层面的开发。代码的复用,觉得可以分为以下几个层面
「类的复用」
比如特定的工具类,大小写转换啦,文件读写啦!都可以整理成工具类库;快速使用,减少不必要的开发;
「设计模式的运用」
熟练的运用设计模式,将业务抽象,将功能抽离,让其更具备扩展性和复用性;
「框架」
将某个特定的模块,以框架的形式抽离,让他独立起来;然后从中暴露特定的类;使用方可以通过这些暴露的类,去与这些框架建立联系并使用其中的功能。
「扩展性强」
你为什么会讨厌需要变更?
产品的迭代,总是会经历一个过程,没有谁会一开始就将产品的细节想的清清楚楚,所以,产品需要的更新迭代是必然会经历的一个过程;那到底是什么让你那么不爽呢?最重要的一个原因就是改动太大;如果每个需求的调整,你只需要添加一个方法、或者添加一个类就能解决了,那你会不开心吗?你不会!
所以优秀开发写的代码是具有很强的扩展性,从一开始就运用设计模式埋下了未来可能出现的扩展点,来应付将来可能出现的产品调整;这样,就算将来有一天真的需要改,也就能从容不迫的去面对。
什么影响着设计模式的学习?
「太难了」
设计模式更多的是偏理论,在学习的过程中;经常会有种错觉,貌似理论看明白了,但是真正上手去写,发现就无从下手。遇到这个问题,归根究底,还是没有悟透,还差点火候。
「没啥用?」
我又不是架构师,我学那玩儿有啥用?
我不会设计模式,好像正常的业务开发也没啥影响呢!
其实日常的开发中,「我们几乎无时无刻都在用设计模式」,不管是用其他人的框架,还是自己的业务代码;很多时候只是我们没有留意或者没有意识到这就是设计模式;
哪怕是一段比较烂的代码,其中可能也用到了某些设计模式,只是没有用好而已。
所以,不要认为,只有架构师才需要学这个;学好设计模式,不管是对你日常开发、开始框架搭建,都会起到至关重要的作用;再说,就算你现在不是架构师,将来你也要成为架构师的撒。
设计模式的分类
23种设计模式 + 简单工厂
按目的划分
「创建型」
用来描述“如何创建一个对象”;就是说将对象的创建过程和使用过程分离开来;GoF设计模式中的创建型:
单例模式
、原型模式
、工厂方法模式
、抽象工厂模式
、建造者模式
;外加简单工厂模式
「结构型」
如何将类、对象按一定要求、规则构建成一个更大、有组织的结构体;便于更方便的使用;GoF设计模式中的结构型:
代理模式
、适配器模式
、桥接模式
、装饰器模式
、外观模式
、享元模式
、组合模式
;「行为型」
用来组织、描述类或对象之间的相互协作、责任划分;共同来完成单个对象无法完成的事情;GoF设计模式中的行为型:
模板方法模式
、策略模式
、命令模式
、责任链模式
、状态模式
、观察者模式
、中介者模式
、迭代器模式
、访问者模式
、备忘录模式
、解释器模式
按作用范围划分
作用于「类」
用于确认类与子类之间的关系,这种关系是通过继承建立的,是一种静态的关系,在代码编译的时候,就已经确认了这种关系;工厂方法、(类)适配器、模板方法、解释器属于该类型的模式;
作用于「对象」
用于组织对象之间的关系,通过组合或聚合,去完成单个类无法完成的任务,这个组合过程,在运行的过程中是允许变化的,因此具有一定的动态性;除了上面说到的四种模式,其他的都属于该类型的模式。
各个模式的功能
这里简单的介绍一下每个模式的作用;后续会对每一个模式以单独的文章再展开详细的介绍。
「单例模式(Singleton)」
确保一个类在一个进程中只会存在一个实例;该类会提供一个方法作为全局的访问点,来供使用方获取对应的实例;
「原型模式(Prototype)」
将一个对象作为原型,通过复制的方式,克隆出多个和目标实例类似的新实例;
「简单工厂模式(Simple Factory)」
定义一个工厂类,他可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类
「工厂方法模式(Factory Method)」
定义一个具体功能相关的接口,由子类来决定这么实现;可以理解为,定义一个行业标准,具体以什么样的方式生成商品我不管,由你各自的工厂自行决定;最后生成出来的产品,符合我的规范即可。
「抽象工厂模式(Abstract Factory)」
提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。
「建造者模式(Builder)」
将一个复杂实例的创建过程拆解成多个小的步骤,然后在真正实例化对象的时候,按照需要,拼接各个需要的步骤并组成一个复杂的对象;
「代理模式(Proxy)」
为实例对象提供一个代理对象,用来控制对目标对象的访问;调用方访问的是代理对象的方法,再由代理对象去访问目标对象的具体方法;因为有代理对象的存在,就可以通过代理对象对目标对象进行校验、控制、调整等操作;
「适配器模式(Adapter Class/Object)」
将一个类的接口,通过适配器,转换成另外一个接口,从而实现两个不相关的接口之间能够协调工作;比如:美版的iphone充电头不能在国内的插板上面充电,就可以在网上买个转换头,转换一下,就可以正常充电了。
「桥接模式(Bridge)」
将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
「装饰器模式(Decorator)」
为对象动态的添加一些职责,从而添加一些额外的功能;就好比游戏中的装备,一个角色代表一个对象,各个部位的装备(头盔、护甲、披风、鞋子、腰带等)都是附加的装饰,并且能添加一个额外的加成;就可以通过装饰者模式来完成;
「外观模式(Facade)」
为多个复杂的子类提供一个一致的接口,以方便调用方使用;
「享元模式(Flyweight)」
通过共享的方式来完成大量细粒度的对象的复用;来提高系统的可复用性;
「组合模式(Composite)」
将对象的组合成树状结构,使使用者对单个对象或多个对象的访问具有一致性;
「模板方法模式(Template Method)」
对外提供一个业务执行流程的骨架方法,骨架方法中定义了业务抽象出来的执行顺序、操作方式;而具体方法的实现,就下放到各个子列去根据实际的业务需求进行实现;调用方调用的是骨架方法,代码会根据骨架方法中指定的顺序,以此调用子类中的实现,完成业务;
「策略模式(Strategy)」
定义一系列的算法,并将这些算法给封装起来,保证他们具有可替换性,当遇到不同的常见,替换不同的算法,而不影响用户的使用;比如网站的背景图片,不同的节日,有不同的背景,我们可以将不同的节日定义一种策略,并指定对应节日的背景图;调用方使用的使用,发现今天是圣诞节,那就使用圣诞节的策略返回;如果是元旦节,就是用元旦节的策略返回。
「命令模式(Command)」
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。
「责任链模式(Chain of Responsibility)」
把请求从链中的一个对象传到下一个对象,直到请求被响应为止;通过这种方式去除对象之间的耦合。典型的案例就是企业OA系统的审批,当没有权限审批的时候,就交由上级领导审批,直到由审批权限的领导为止;
「状态模式(State)」
允许一个对象在其内部状态发生改变时改变其行为能力。
「观察者模式(Observer)」
当对象出现一对多的关系时,当一个对象发生变化时,会主动通知其他实例,从而改变其他实例的行为;比如:微服务中的注册中心,当一个服务下线之后,注册中心就会通知其他关联的服务,让其他模块不再调用这个已经下线的模块了。
「中介者模式(Mediator)」
定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。
「迭代器模式(Iterator)」
提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
「访问者模式(Visitor)」
在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。
「备忘录模式(Memento)」
在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。
「解释器模式(Interpreter)」
提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。
如何学好设计模式呢?
「多看」
何为多看?学习设计模式并不像用某个框架那么简单,会使用某个API就好了;
他是需要一个闭关修炼的过程,多看、多想、多思考。
多看优秀的框架代码,多想想优秀的框架对设计模式的运用,然后再结合自己的业务去思考,如何运用的自己的业务开发中来。
「多写」
脑子说:我会了!
手说:你不对!
这也是经常会遇到的一种情况;人的大脑是有「浅记忆」和「深度记忆」的,当你去看别人写的代码时,形成的只是浅记忆,可能当时记住了,但是过了一段时间就忘记了;
同时看的过程会忽略某一些细小的细节;看似看明白了,其实并没有真正的理解透彻;只有真正自己动手去写每一行代码的时候,才能发现其中的细节,也才能将理解变成深度记忆并熟练运用。
「多运用」
当我们对设计模式使用不熟悉的时候,要尝试着多运用设计模式;通过时间去积累,从而产生质变;
我想每个程序员都应该有过“顿悟”的经历,突然某一个瞬间的一行代码,让你彻底想明白曾经纠结的好久的问题;那么这就是量变带来的效果。
「避免过度设计」
设计模式的初衷是为了提高代码的
可复用性
、可维护性
、可读性
、稳健性
以及安全性
;但是在使用设计模式的过程中不可避免的会增加代码的复杂度;
如果你发现一顿“操作”之后,并没有让代码变的简单,反而让他更复杂;加了设计模式之后,带来了得不偿失的效果,那么我劝你就不要加的;很可能你当前做的产品,就不适合使用设计模式;也可能是“邯郸学步”,并没有利用好对的设计模式。
「谁是最好的设计模式?」
上面列了那么多设计模式,谁才是最好的设计模式呢?
其实并没有什么最好的设计模式,只有最合适的设计模式!每种设计模式都会是某个特殊场景下的最佳实践;
而且,日常使用中,设计模式从来都不会单个模式独立使用,更多的是多个模式相互配合,查缺补漏,你中有我,我中有你,从而达到方案的最优解。
对象对象的设计原则
为了能更好的运用设计模式,提高系统的灵活性、扩展性,我们必须遵循以下的7大原则:
开闭原则
里氏替换原则
依赖导致原则
单一职责原则
接口隔离原则
迪米特法则
合成复用原则
到这里,我们对设计模式的重要性、分类、特点、设计原则都有了一定的了解;接下来的一段时间,会将上面说到的点通过详细的代码示例,逐一的进行讲解。
敬请持续关注!
End
最近开发整理了一个用于速刷面试题的小程序;其中收录了上千道常见面试题及答案(包含基础、并发、JVM、MySQL、Redis、Spring、SpringMVC、SpringBoot、SpringCloud、消息队列等多个类型),欢迎您的使用。QQ交流群:912509560
感谢您的点赞、在看、星标